<template>
<div class="y-table" :class="[border && 'y-table--border', stripe && 'y-table--stripe']">
  <div class="y-table__header-wrap" ref="headerWrap">
    <table :style="{transform: `translateX(${-this.bodyScrollLeft}px)` }">
      <colgroup>
        <col
          v-for="col in fixedColumns"
          :key="col.prop"
          :width="col.width + 'px'"
        />
        <col v-if="hasScrollableY" :width="scrollBarWidth + 'px'" />
      </colgroup>
      <thead>
        <tr>
          <th ref="headerCell" v-for="col in fixedColumns" :key="col.prop">
            {{col.label}}
          </th>
          <th v-if="hasScrollableY" class="y-table__gutter"></th>
        </tr>
      </thead>
    </table>
  </div>
  <div ref="bodyWrap" class="y-table__body-wrap" :style="bodyWrapStyle" @scroll="debounceScroll">
    <table ref="body">
      <colgroup>
        <col
          v-for="col in fixedColumns"
          :key="col.prop"
          :width="col.width + 'px'"
        />
      </colgroup>
      <tbody>
        <tr v-for="(data, index) in dataSource" :key="index">
          <td ref="bodyCell" v-for="col in fixedColumns" :key="col.prop">
            {{data[col.prop]}}
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
</template>
<script>
import { debug, rAF } from '../src/util'
import scrollBarWidth from './scrollbar-width'
import interact from 'interactjs'
const log = debug({
  prefix: 'y-table:',
  disabled: true,
})
export default {
  name: 'y-table',
  props: {
    dataSource: {
      type: Array,
      default() {
        return []
      },
    },
    columns: {
      type: Array,
      required: true,
    },
    border: {
      type: Boolean,
      default: false
    },
    stripe: {
      type: Boolean,
      default: false
    },
    height: {
      type: Number
    }
  },
  data () {
    return {
      // 是否已经 mounted
      isMounted: false,
      // 是否有垂直滚动条
      hasScrollableY: false,
      // 初始 headerWrap 的高度
      initHeaderWrapHeight: 0,
      // 内容的高度
      bodyWrapHeight: 0,
      // 滚动条的宽度
      scrollBarWidth: scrollBarWidth(),
      // 经过处理的列的定义
      fixedColumns: this.columns,
      // body 横向滚动
      bodyScrollLeft: 0,
      totalColumnsWidth: 0,
    }
  },
  computed: {
    bodyWrapStyle() {
      return {
        height: this.bodyWrapHeight && this.bodyWrapHeight + 'px'
      }
    },
  },
  watch: {
    height () {
      this.$nextTick(() => {
        this.initHeight()
        this.initColumnWidth()
      })
    },
    columns: {
      immediate: true,
      handler (value) {
        this.fixedColumns = value
        this.$nextTick(() => {
          // log('==== columns change ====', JSON.stringify(value, null, 2))
          this.initColumnWidth()
          this.bindResize()
        })
      }
    },
    dataSource: {
      handler () {
        this.$nextTick(() => {
          log('==== dataSource change ====')
          this.initHeight()
        })
      }
    }
  },
  methods: {
    // 计算内容的高度，是否有滚动条
    initHeight() {
      if (!this.isMounted) return false
      log('************ initHeight ************')
      let bodyHeight = this.$refs.body.offsetHeight
      log('get bodyHeight:', bodyHeight)
      if (this.height) {
        this.bodyWrapHeight = this.height - this.initHeaderWrapHeight
        // 如果设置的高度小于表格本身的高度则会产生垂直滚动条并且表头固定
        if (this.bodyWrapHeight < bodyHeight) {
          this.hasScrollableY = true
        } else {
          this.hasScrollableY = false
        }
      } else {
        this.bodyWrapHeight = this.bodyHeight
        this.hasScrollableY = false
      }
    },
    // 计算每列的宽度
    initColumnWidth() {
      if (!this.isMounted) return false
      // let gridWidth = this.$refs.bodyWrap.offsetWidth
      this.$nextTick(() => {
        log('************ initColumnWidth ************')
        let cells = this.$refs.bodyCell || this.$refs.headerCell || [];
        this.fixedColumns = this.columns.map((column, index) => {
          let width = cells[index] && cells[index].offsetWidth
          return {
            ...column,
            width
          }
        })
        this.totalColumnsWidth = this.fixedColumns.reduce((acc, column) => {
          acc += column.width
          return acc;
        }, 0)
        // log('fixedColumns: ', JSON.stringify(this.fixedColumns, null, 2))
      })
    },
    // 处理滚动
    debounceScroll (e) {
      this.scrollLeft(e)
    },
    scrollLeft: rAF(function (e) {
      this.bodyScrollLeft = e.target.scrollLeft
    }),
    // 绑定改变大小
    bindResize () {
      log('bindResize', this.$refs.headerCell)
      this.$refs.headerCell && this.$refs.headerCell.forEach((item, index) => {
        interact(item).resizable({
          edges: {right: true},
          inertia: true,
        }).on('resizemove', event => {
           console.log('resize: ', event.rect.width)
           this.changeSize(index, event.rect.width)
        })
      })
    },
    changeSize (index, newWidth) {
      let diffWidth = 0
      this.fixedColumns = this.fixedColumns.map((column, idx) => {
        let oldWidth = column.width
        if ( idx < index) {
          return column
        } else if (idx === index) {
          diffWidth = oldWidth - newWidth
          return {
            ...column,
            width: newWidth
          }
        } else  {
          if (diffWidth > 0 && idx === index + 1) {
            return {
              ...column,
              width: oldWidth - diffWidth
            }
          } else {
            return column
          }
        }
      })
    }
  },
  mounted () {
    log('mounted - start')
    this.isMounted = true
    this.initHeaderWrapHeight = this.$refs.headerWrap.offsetHeight
    this.initHeight()
    this.initColumnWidth()
    this.bindResize()
    log('mounted - finish')
  }
}
</script>
<style lang="scss">
// $border-color: #ebeef5;
$border-color: #607D8B;
$tr-hover-color: scale-color($border-color, $lightness: 30%);

.y-table {
    overflow: hidden;
    box-sizing: border-box;
    position: relative;
    font-size: 14px;
    color: #606266;
    background: #fff;
    border: 1px solid $border-color;
    table {
      width: 100%;
      border-collapse: collapse;
      border-spacing: 0;
      box-sizing: border-box;
      table-layout: fixed;
      th, td {
        text-align: left;
        border-bottom: 1px solid $border-color;
        padding: 10px;
        touch-action: none;
        box-sizing: border-box;
      }
    }
    &.y-table--border {
      table {
        th, td {
          border-bottom: 1px solid $border-color;
          border-right: 1px solid $border-color;
          &:last-child {
            border-right: 0;
          }
        }
        tbody {
          tr:last-child td{
            border-bottom: 0;
          }
        }
      }
    }
    &.y-table--stripe {
      tbody {
        tr:nth-child(2n) {
          background-color: $tr-hover-color;
        }
      }
    }
    .y-table__body-wrap {
      overflow: auto;
    }
}
</style>
